﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OvercomingShyness
{
    public static class StandardDelegates
    {
        public static void RegisterAll(BadKeyMachine pMachine)
        {
            pMachine.Register("+", Add);
            pMachine.Register("-", Subtract);
            pMachine.Register("*", Multiply);
            pMachine.Register("/", Divide);
            pMachine.Register("%", Mod);
            pMachine.Register("floor", Floor);
            pMachine.Register("**", Power);
            pMachine.Register("sqrt", SquareRoot);
            pMachine.Register("<", LessThan);
            pMachine.Register(">", GreaterThan);
            pMachine.Register("<=", LessThanOrEqual);
            pMachine.Register(">=", GreaterThanOrEqual);
            pMachine.Register("==", Equal);
            pMachine.Register("!=", NotEqual);
            pMachine.Register("&&", And);
            pMachine.Register("||", Or);
            pMachine.Register("!", Not);
            pMachine.Register("debug", Debug);
            pMachine.Register("standard", Standard);
        }

        #region basic math

        public static void Add(BadKeyThread pThread)
        {
            double lNumberAcc = 0;
            string lStringAcc = "";
            int i = 0;
            bool lIsString = false;

            // first check to see if we're adding strings or numbers
            while (pThread.FetchValue("arg" + i) != "zundefined")
            {
                if (pThread.FetchValue("arg" + i).StartsWith("s")
                    || pThread.FetchValue("arg" + i).StartsWith("b")
                    || pThread.FetchValue("arg" + i).StartsWith("z"))
                    lIsString = true;

                i++;
            }

            // accumulate in the appropriate accumulator
            i = 0;
            while (pThread.FetchValue("arg" + i) != "zundefined")
            {
                if (lIsString)
                {
                    lStringAcc += pThread.ToS(pThread.FetchValue("arg" + i));
                }
                else
                {
                    lNumberAcc += pThread.ToN(pThread.FetchValue("arg" + i));
                }

                i++;
            }

            // and return the appropriate value
            if (lIsString)
            {
                pThread.Return("\"" + lStringAcc + "\"");
            }
            else
            {
                pThread.Return("" + lNumberAcc);
            }
        }

        public static void Subtract(BadKeyThread pThread)
        {
            double lAcc = pThread.ToN(pThread.FetchValue("arg0"));

            int i = 1;
            while (pThread.FetchValue("arg" + i) != "zundefined")
            {
                lAcc -= pThread.ToN(pThread.FetchValue("arg" + i));
                i++;
            }

            pThread.Return("" + lAcc);
        }

        public static void Multiply(BadKeyThread pThread)
        {
            double lAcc = pThread.ToN(pThread.FetchValue("arg0"));

            int i = 1;
            while (pThread.FetchValue("arg" + i) != "zundefined")
            {
                lAcc *= pThread.ToN(pThread.FetchValue("arg" + i));
                i++;
            }

            pThread.Return("" + lAcc);
        }

        public static void Divide(BadKeyThread pThread)
        {
            double lAcc = pThread.ToN(pThread.FetchValue("arg0"));

            int i = 1;
            while (pThread.FetchValue("arg" + i) != "zundefined")
            {
                lAcc /= pThread.ToN(pThread.FetchValue("arg" + i));
                i++;
            }

            pThread.Return("" + lAcc);
        }

        #endregion

        #region advanced math

        public static void Mod(BadKeyThread pThread)
        {
            double lVal1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lVal2 = pThread.ToN(pThread.FetchValue("arg1"));

            pThread.Return("" + (lVal1 % lVal2));
        }

        public static void Floor(BadKeyThread pThread)
        {
            double lVal1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lVal2 = pThread.ToN(pThread.FetchValue("arg1"));

            pThread.Return("" + (lVal1 - (lVal1 % lVal2)));
        }

        public static void Power(BadKeyThread pThread)
        {
            double lVal1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lVal2 = pThread.ToN(pThread.FetchValue("arg1"));

            pThread.Return("" + Math.Pow(lVal1, lVal2));
        }

        public static void SquareRoot(BadKeyThread pThread)
        {
            double lVal = pThread.ToN(pThread.FetchValue("arg0"));

            pThread.Return("" + Math.Sqrt(lVal));
        }

        #endregion

        #region boolean

        public static void And(BadKeyThread pThread)
        {
            bool lCompare1 = pThread.ToB(pThread.FetchValue("arg0"));
            bool lCompare2 = pThread.ToB(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 && lCompare2);
            pThread.Return(lResult);
        }

        public static void Or(BadKeyThread pThread)
        {
            bool lCompare1 = pThread.ToB(pThread.FetchValue("arg0"));
            bool lCompare2 = pThread.ToB(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 || lCompare2);
            pThread.Return(lResult);
        }

        public static void Not(BadKeyThread pThread)
        {
            bool lCompare1 = pThread.ToB(pThread.FetchValue("arg0"));            
            string lResult = "" + !lCompare1;
            pThread.Return(lResult);
        }

        #endregion

        #region comparison

        public static void LessThan(BadKeyThread pThread)
        {
            double lCompare1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lCompare2 = pThread.ToN(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 < lCompare2);
            pThread.Return(lResult);
        }

        public static void GreaterThan(BadKeyThread pThread)
        {
            double lCompare1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lCompare2 = pThread.ToN(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 > lCompare2);
            pThread.Return(lResult);
        }

        public static void LessThanOrEqual(BadKeyThread pThread)
        {
            double lCompare1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lCompare2 = pThread.ToN(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 <= lCompare2);
            pThread.Return(lResult);
        }

        public static void GreaterThanOrEqual(BadKeyThread pThread)
        {
            double lCompare1 = pThread.ToN(pThread.FetchValue("arg0"));
            double lCompare2 = pThread.ToN(pThread.FetchValue("arg1"));
            string lResult = "" + (lCompare1 >= lCompare2);
            pThread.Return(lResult);
        }

        public static void Equal(BadKeyThread pThread)
        {
            string lCompare1 = pThread.FetchValue("arg0");
            string lCompare2 = pThread.FetchValue("arg1");
            pThread.Return("" + (lCompare1.Equals(lCompare2)));
        }

        public static void NotEqual(BadKeyThread pThread)
        {
            string lCompare1 = pThread.FetchValue("arg0");
            string lCompare2 = pThread.FetchValue("arg1");
            pThread.Return("" + (!lCompare1.Equals(lCompare2)));
        }

        #endregion

        public static void Debug(BadKeyThread pThread)
        {
            System.Diagnostics.Debug.WriteLine(pThread.ToS(pThread.FetchValue("arg0")));
            pThread.Return();
        }

        /// <summary>
        /// not a real thing. used for 'requiring "standard"'
        /// </summary>
        /// <param name="pThread"></param>
        public static void Standard(BadKeyThread pThread)
        {
            pThread.Return();
        }
    }
}